package com.sergio.accounting.util;

import com.sergio.accounting.entity.User;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

/**
 * JWT工具类
 */
@Slf4j
@Component
public class JwtUtil {

    @Value("${jwt.secret}")
    private String secret;

    @Value("${jwt.expiration}")
    private Long expiration;

    /**
     * 从token中提取用户名
     */
    public String extractUsername(String token) {
        return extractClaim(token, Claims::getSubject);
    }

    /**
     * 从token中提取过期时间
     */
    public Date extractExpiration(String token) {
        return extractClaim(token, Claims::getExpiration);
    }

    /**
     * 从token中提取指定声明
     */
    public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = extractAllClaims(token);
        return claimsResolver.apply(claims);
    }

    /**
     * 从token中提取所有声明
     */
    private Claims extractAllClaims(String token) {
        try {
            if (secret == null || secret.trim().isEmpty()) {
                log.error("JWT secret未配置");
                return null;
            }
            
            return Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (io.jsonwebtoken.ExpiredJwtException e) {
            log.warn("JWT token已过期: {}", e.getMessage());
            return null;
        } catch (io.jsonwebtoken.MalformedJwtException e) {
            log.error("JWT token格式错误: {}", e.getMessage());
            return null;
        } catch (io.jsonwebtoken.SignatureException e) {
            log.error("JWT token签名验证失败: {}", e.getMessage());
            return null;
        } catch (io.jsonwebtoken.UnsupportedJwtException e) {
            log.error("不支持的JWT token: {}", e.getMessage());
            return null;
        } catch (IllegalArgumentException e) {
            log.error("JWT token参数错误: {}", e.getMessage());
            return null;
        } catch (Exception e) {
            log.error("解析JWT token时发生未知错误: {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 检查token是否过期
     */
    private Boolean isTokenExpired(String token) {
        return extractExpiration(token).before(new Date());
    }

    /**
     * 为用户生成token
     */
    public String generateToken(User user) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", user.getId());
        claims.put("username", user.getUsername());
        // 添加更多唯一性标识
        long loginTime = System.currentTimeMillis();
        String randomId = java.util.UUID.randomUUID().toString();
        claims.put("loginTime", loginTime);
        claims.put("randomId", randomId);
        
        log.info("生成JWT token - 用户: {}, 用户ID: {}, 登录时间: {}, 随机ID: {}", 
                user.getUsername(), user.getId(), loginTime, randomId);
        
        return createToken(claims, user.getUsername());
    }

    /**
     * 创建token
     */
    private String createToken(Map<String, Object> claims, String subject) {
        long currentTime = System.currentTimeMillis();
        Date issuedAt = new Date(currentTime);
        Date expirationDate = new Date(currentTime + this.expiration);
        
        String token = Jwts.builder()
                .setClaims(claims)
                .setSubject(subject)
                .setIssuedAt(issuedAt)
                .setExpiration(expirationDate)
                .signWith(SignatureAlgorithm.HS256, secret)
                .compact();
        
        log.debug("JWT token创建完成 - 主题: {}, 签发时间: {}, 过期时间: {}, token长度: {}", 
                subject, issuedAt, expirationDate, token.length());
        
        return token;
    }

    /**
     * 验证token
     */
    public Boolean validateToken(String token, String username) {
        final String extractedUsername = extractUsername(token);
        return (username.equals(extractedUsername) && !isTokenExpired(token));
    }

    /**
     * 从token中提取用户ID
     */
    public Long extractUserId(String token) {
        try {
            if (token == null || token.trim().isEmpty()) {
                log.warn("JWT token为空");
                return null;
            }
            
            Claims claims = extractAllClaims(token);
            if (claims == null) {
                log.warn("无法解析JWT claims");
                return null;
            }
            
            Object userIdObj = claims.get("userId");
            if (userIdObj == null) {
                log.warn("JWT claims中未找到userId字段");
                return null;
            }
            
            Long userId;
            if (userIdObj instanceof Long) {
                userId = (Long) userIdObj;
            } else if (userIdObj instanceof Integer) {
                userId = ((Integer) userIdObj).longValue();
            } else if (userIdObj instanceof String) {
                try {
                    userId = Long.parseLong((String) userIdObj);
                } catch (NumberFormatException e) {
                    log.error("无法将userId字符串转换为Long: {}", userIdObj);
                    return null;
                }
            } else {
                log.error("userId字段类型不支持: {}", userIdObj.getClass().getName());
                return null;
            }
            
            log.debug("从JWT token中提取用户ID: {}", userId);
            return userId;
        } catch (Exception e) {
            log.error("提取用户ID失败: {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 刷新token
     */
    public String refreshToken(String token) {
        final Claims claims = extractAllClaims(token);
        claims.setIssuedAt(new Date());
        return createToken(claims, claims.getSubject());
    }
}
